﻿//#define SHAREMEM
#define IN_CONSOLE

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Collections;
using System.Runtime.InteropServices;


namespace InterTech
{
    public enum LeakTesterType { M1075, M1075Y };
    public class LeakTester
    {
        public LeakTesterType ModuleType;
        public LeakResult testResult;
        private SerialPort ComPort;
        bool FoundM=false;
        public bool Converted = false;
        public bool Got0x0D = false;
        public bool RecordRawData = false;
        byte OldBuffEnd=0;
        protected  Queue<byte[]> QueueFromSerial;//用于存放从Com口读出来的数据队列。
        //protected static byte [] LastStrFromSerial=new byte [4];
        public string StrFromSerial = "";//将从Com口读出来的数据队列转化成的字符串


        #region------------初始化测试仪-----------
#if SHAREMEM
        private static IntPtr pMonitorProcess;
        public LeakTester(IntPtr MonitorProcessID)
        {
            pMonitorProcess = MonitorProcessID;
#else
        public LeakTester()
        {
#endif
        
#if SHAREMEM
            pMonitorProcess = MonitorProcessID;
#endif
        }

        public void InitLeakTester(LeakTesterType leaktestertype, System.IO.Ports.SerialPort comport, int timerInterval/*, string strStart, string strEnd*/)
        {
            try
            {
                ModuleType = leaktestertype;
                ComPort = comport;
                ComPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.serialDataReceived);
                SetSerialPort(true);
                QueueFromSerial = new Queue<byte []>();
            }
            catch (Exception ex)
            {
                General.LogFunc.LogWrite(ex.ToString(), General.Info.GetCurrentDirctory() + "Err_InitLeakTester.log");
            }
        }
        #endregion

        /// <summary>串口数据到达的响应事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int length;
            string filename = @"C:\" + this.ComPort.PortName+"0000.log";
            byte[] buff = new byte[1024];

            try
            {
                if (((SerialPort)sender).BytesToRead > 0)
                {
                    length = ((SerialPort)sender).Read(buff, 0, ((SerialPort)sender).BytesToRead);
                    Array.Resize<byte>(ref buff, length);
                    if (RecordRawData) using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Append))
                        {
                            fs.Write(buff, 0, buff.Length);
                            fs.Close();
                        }
                    if (buff.Length > 0)
                    {
                        QueueFromSerial.Enqueue(buff);
                        if (buff.Contains((byte)0x0D)) Got0x0D = true;
                    }
                    //if(buff [length]==0xff)
#if SHAREMEM
                pMonitorProcess=WinAPI.Process.GetClientMainFromHandle(LTA_RawData.Common.MonitorProcessName);
                ShareMemory.Server.WriteMapping(this.ComPort.PortName + convert.GetString(buff, 0, length), LTA_RawData.Common.pLT_MEM);
                WinAPI.Message.TellClentDataReady(pMonitorProcess);
#endif
                }
                //else General.LogFunc.LogWriteInDay(this .ComPort .PortName + " Strange: BytesToRead not >0");
            }
            catch (Exception ex)
            {
                General.LogFunc.LogWrite(ex.ToString(), General.Info.GetCurrentDirctory() + "Err_serialDataReceived.log");
            }
        }
        #region ----------------数据获取或处理ConvertStrToData--------------------

        public int FindString()
        {
            switch (this.ModuleType)
            { 
                case LeakTesterType .M1075 :
                    return FindUsefullString_M1075();
                    
                case LeakTesterType .M1075Y :
                    return FindUsefullString_M1075Y();
                    
                default:
                    return -3;
                    
            }
        }

        /// <summary>把队列里的数据组合，并查找是否包含完整的测试结果，如果包含，则调用ConvertStrToData，将结果存储在LeakResult里面。
        /// </summary>
        /// <returns>0：队列里没有数据；1：转换成功；-3：待转换的字符串格式不正确</returns>
        public int FindUsefullString_M1075Y()
        {
            int i=0;
            string sReceived;
            byte[] buff=new byte [1024];
            
            System.Text.ASCIIEncoding convert = new ASCIIEncoding();
            Got0x0D = false;
            try
            {
                if (QueueFromSerial.Count == 0) return 0;//没有数据
#if IN_CONSOLE
               // Console.WriteLine(this.ComPort.PortName + " Finding...");     
#endif                
                while (QueueFromSerial.Count > 0)
                {
                    buff = QueueFromSerial.Dequeue();
                    //Console.WriteLine(convert .GetString (buff ) );
                    
                    if (FoundM != true)//前几次没有找到M
                    {
                        for (i = 0; i < buff.Length; i++)
                        {
                            if (buff[i] == 0x4D)//找到了“M”
                            {
                                if (i > 0)
                                {
                                    if (buff[i - 1] == 0xFF) FoundM = true;
                                }
                                else
                                {
                                    if (OldBuffEnd == 0xff) FoundM = true;
                                }
                                break;
                            }
                        }
                        if (i < buff.Length)
                        {
                            sReceived = convert.GetString(buff, i, buff.Length - i);  //刚刚找到了"M"
                            StrFromSerial = sReceived;
                            continue;
                        }
                    }
                    else //找到了M
                    {
                        for (i = 0; i < buff.Length; i++)
                        {
                            if (buff[i] == 0x0D)//找到了“0xFF”
                            {
                                //sReceived = convert.GetString(buff, 0, i);
                                //StrFromSerial = StrFromSerial + sReceived;
                                FoundM = false;

                                break;
                            }

                        }
                            sReceived = convert.GetString(buff, 0,i);
                            StrFromSerial = StrFromSerial + sReceived;
                            if (!FoundM)//找到了0xFF
                            {
                                this.testResult = this.ConvertStrToData(StrFromSerial);
                                Console.WriteLine("Data: " + StrFromSerial);
                                if (this.testResult.Leakage == "-9999")
                                {
                                    Converted = false;
                                    return -3;
                                }
                                

                                Converted = true;
                                return 1;
                            }
                    }
                    OldBuffEnd = buff[buff.Length - 1];
                }
                return 0;
                
                
            }
            catch (Exception ex)
            {

                General.LogFunc.LogWrite(ex.ToString(), General.Info.GetCurrentDirctory() + "Err_FindUsefullString.log");

                return -1;
            }
        }
        /// <summary>把队列里的数据组合，并查找是否包含完整的测试结果，如果包含，则调用ConvertStrToData，将结果存储在LeakResult里面。
        /// </summary>
        /// <returns>0：队列里没有数据；1：转换成功；-3：待转换的字符串格式不正确</returns>
        public int FindUsefullString_M1075()
        {
            int i = 0;
            string sReceived;
            byte[] buff = new byte[1024];

            System.Text.ASCIIEncoding convert = new ASCIIEncoding();
            Got0x0D = false;
            try
            {
                if (QueueFromSerial.Count == 0) return 0;//没有数据
#if IN_CONSOLE
                // Console.WriteLine(this.ComPort.PortName + " Finding...");     
#endif
                while (QueueFromSerial.Count > 0)
                {
                    buff = QueueFromSerial.Dequeue();
                    //Console.WriteLine(convert .GetString (buff ) );

                    if (FoundM != true)//前几次没有找到M
                    {
                        for (i = 0; i < buff.Length; i++)
                        {
                            if (buff[i] == 0x4D)//找到了“M”
                            {
                                if (i > 0)
                                {
                                    if (buff[i - 1] == 0x80) FoundM = true;
                                }
                                else
                                {
                                    if (OldBuffEnd == 0x80) FoundM = true;
                                }
                                break;
                            }
                        }
                        if (i < buff.Length)
                        {
                            sReceived = convert.GetString(buff, i, buff.Length - i);  //刚刚找到了"M"
                            StrFromSerial = sReceived;
                            continue;
                        }
                    }
                    else //找到了M
                    {
                        for (i = 0; i < buff.Length; i++)
                        {
                            if (buff[i] == 0x0D)//找到了“0xFF”
                            {
                                //sReceived = convert.GetString(buff, 0, i);
                                //StrFromSerial = StrFromSerial + sReceived;
                                FoundM = false;

                                break;
                            }

                        }
                        sReceived = convert.GetString(buff, 0, i);
                        StrFromSerial = StrFromSerial + sReceived;
                        if (!FoundM)//找到了0xFF
                        {
                            this.testResult = this.ConvertStrToData(StrFromSerial);
                            Console.WriteLine("Data: " + StrFromSerial);
                            if (this.testResult.Leakage == "-9999")
                            {
                                Converted = false;
                                return -3;
                            }


                            Converted = true;
                            return 1;
                        }
                    }
                    OldBuffEnd = buff[buff.Length - 1];
                }
                return 0;


            }
            catch (Exception ex)
            {

                General.LogFunc.LogWrite(ex.ToString(), General.Info.GetCurrentDirctory() + "Err_FindUsefullString.log");

                return -1;
            }
        }
        /// <summary>仅用来供FindUsefullString调用，将字符串转换成测试结果，格式如下：
        /// M000,01,01,model-1   ,09-13-2012,02:22:39,+0004.01,+000.009,AC   >>>>>For new leak tester
        /// M000,01,StANDARD  ,09-20-2012,23:15:12,-0.035,AC                 >>>>>For Old Leak tester
        /// 01234567891123456789212345678931234567894123456789512345678961
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private LeakResult ConvertStrToData(string str)
        {
            LeakResult resTemp = new LeakResult();
            string sTemp;
            string[] strArray;
            resTemp.Module = "UnKnown";
            resTemp.Date = "1983-05-25";
            resTemp.Time = "08:15:00";
            resTemp.Press = "-9999";
            resTemp.Leakage = "-9999";
            resTemp.Status = "NA";
            try
            {
                Converted = false;
                switch (ModuleType)
                {
                    case LeakTesterType.M1075Y:
                        {
                            if (str.Length == 62)
                            {
                                strArray = str.Split(',');
                                resTemp.Module = strArray[3];
                                resTemp.Date = strArray[4];
                                resTemp.Time = strArray[5];
                                resTemp.Press = strArray[6];
                                resTemp.Leakage = strArray[7];
                                resTemp.Status = strArray[8];
#if IN_CONSOLE
                                Console.Write(this.ComPort.PortName + "--> ");
#endif
                                Converted = true;

                            }
                            if (str.Length < 62)
                            {
                                //Console.Write(this.ComPort.PortName + "OK!\r\n");
                                General.LogFunc.LogWriteInDay(this.ComPort.PortName + " length "+ str.Length .ToString () +" not enough\r\n" + str);
                                return resTemp;
                            }
                            if (str.Length > 62)
                            {
#if IN_CONSOLE
                                //Console.WriteLine("\r\n" + this.ComPort.PortName + " Data:\r\n" + str);
#endif
                                sTemp = str.Substring(str.LastIndexOf('M'));
                                if (sTemp.Length == 64)
                                {
                                    strArray = str.Split(',');
                                    resTemp.Module = strArray[3];
                                    resTemp.Date = strArray[4];
                                    resTemp.Time = strArray[5];
                                    resTemp.Press = strArray[6];
                                    resTemp.Leakage = strArray[7];
                                    resTemp.Status = strArray[8];
#if IN_CONSOLE
                                    Console.WriteLine("Convert success\r\n"+str);
#endif
                                    General.LogFunc.LogWriteInDay("Convert success:\r\n"+str+"\r\n");
                                }
                                else
                                {
                                    General.LogFunc.LogWriteInDay(this.ComPort.PortName + " length " + str.Length.ToString() + " not enough\r\n" + str + "\r\n");
                                    return resTemp;
                                }
                            }
                            break;
                        }
                    case LeakTesterType.M1075:   //  case LeakTesterType.M1075:
                        {
                            if (str.Length != 48)
                            {
                                General.LogFunc.LogWriteInDay(this.ComPort.PortName + " length " + str.Length.ToString() + " not enough\r\n" + str);
                                return resTemp;
                            }
                            strArray = str.Split(',');
                            resTemp.Module = strArray[2];
                            resTemp.Date = strArray[3];
                            resTemp.Time = strArray[4];
                            resTemp.Press = "-9999";
                            resTemp.Leakage = strArray[5];
                            resTemp.Status = strArray[6];
#if IN_CONSOLE
                            Console.Write(this.ComPort.PortName + "--> ");
#endif
                            break;
                        }
                    default:
                        {
                            break;
                        }
                }
                resTemp.DateTime = ConvertDateTime(Convert.ToDateTime(resTemp.Date + " " + resTemp.Time));
                return resTemp;
            }
            catch (Exception ex)
            {
                General.LogFunc.LogWrite(ex.ToString(), General.Info.GetCurrentDirctory() + "Err_ConvertStrToData.log");
                return resTemp;
            }
        }


        #endregion

        #region--------------------SetSerialPort,Some Little Functions: ClearData, LogWrite,GetComPortName-------------------
        /// <summary>设置打开或关闭串口
        /// </summary>
        /// <param name="open"></param>
        /// <returns></returns>
        internal int SetSerialPort(bool open)
        {
            try
            {
                if (open)
                {
                    if (!ComPort.IsOpen) ComPort.Open();
                }
                else
                {
                    if (ComPort.IsOpen) ComPort.Close();
                }
                return 0;
            }
            catch (Exception ex)
            {
                General.LogFunc.LogWrite(ex.ToString(), General.Info.GetCurrentDirctory() + "Err_SetSerialPort.log");
                return -1;
            }
        }
        public void ClearData()
        {
            testResult.Module = "";
            testResult.DateTime = "";
            testResult.Press = "";
            testResult.Leakage = "";
            testResult.Status = "";
        }
        
        private string ConvertDateTime(DateTime datetime)
        {
            //1999-11-11 12:22:22
            string year, month, day;
            string time;
            int enddot = 0;
            year = datetime.Year.ToString();
            month = datetime.Month.ToString();
            day = datetime.Day.ToString();
            time = datetime.TimeOfDay.ToString();

            enddot = time.IndexOf('.');
            if (enddot > 0) time = time.Substring(0, time.Length - enddot);
            //return time;
            return year + "-" + month + "-" + day + " " + time;

        }

        internal string GetComPortName()
        {
            return ComPort.PortName;
            //throw new NotImplementedException();
        }
        internal bool IsComOpened()
        {
            return ComPort.IsOpen;
        }
        #endregion

    }

    public struct LeakResult
    {
        public string Module;
        public string DateTime;//1999-11-11 12:22:22
        public string Date;
        public string Time;
        public string Press;
        public string Leakage;
        public string Status;//20130103JM.Liu add
    }

    public struct com1_testparm_type
    {
        public char message_type;// const 'X'
        //channel 1 assumed, multiple channels not supported
        public Int16 part_index;
        public Int16 samples_per_packet;
        public Int16 sample_rate;//in milliseconds

        public UInt32 total_samples;
        public float total_real_time;
        public UInt32 total_long_time;
        public UInt16 pretest_time;
        public UInt16 prebias_time;
        public UInt16 prefill_time;
        public UInt16 fill_time;
        public UInt16 bypass_time;
        public UInt16 stabilize_time;
        public UInt16 test_time;
        public float limit_mainlower;
        public float limit_mainupper;
        public float limit_auxlower;
        public float limit_auxupper;
        public float limit_biaslower;
        public float limit_biasupper;
        public float spare1;
        public float spare2;
        public float spare3;
        public float spare4;
        public eom_type eom;
    }
    public struct eom_type
    {
        public char eom1;
        public char eom2;
        public char eom3;
        public char eom4;
    }
    public struct com1_testdata_type
    {
        public char message_type;//const 'G'
        //channel 1 assumed, multiple channels not supported
        public UInt32 sample_num;
        public float val1;
        public float val2;
        public eom_type eom;
    }



}

[StructLayout(LayoutKind.Explicit, Size = 16, CharSet = CharSet.Ansi)]
public class MySystemTime
{
    [FieldOffset(0)]
    public ushort wYear;
    [FieldOffset(2)]
    public ushort wMonth;
    [FieldOffset(4)]
    public ushort wDayOfWeek;
    [FieldOffset(6)]
    public ushort wDay;
    [FieldOffset(8)]
    public ushort wHour;
    [FieldOffset(10)]
    public ushort wMinute;
    [FieldOffset(12)]
    public ushort wSecond;
    [FieldOffset(14)]
    public ushort wMilliseconds;
}
[Serializable] // 指示可序列化
[StructLayout(LayoutKind.Sequential, Pack = 1)] // 按1字节对齐
public struct Operator
{
    public ushort id;
    // 声明一个字符数组，大小为11
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
    public char[] name;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
    public char[] pass;
    public Operator(string user, string pass) // 初始化
    {
        this.id = 10000;
        this.name = user.PadRight(11, '\0').ToCharArray();
        this.pass = pass.PadRight(9, '\0').ToCharArray();
    }
}
